package org.stbernardpreserve.learning.effectivejava.hashcodeequalstostring;

public class Dog {

	public static enum Breed {
		STBERNARD {
			@Override
			public String toString() {
				return "St. Bernard";
			}
		},
		ROTTWEILER {
			@Override
			public String toString() {
				return "Rottweiler";
			}
		},
		OLD_ENGLISH_MASTIFF {
			@Override
			public String toString() {
				return "Old English Mastiff";
			}
		}

	}

	@SuppressWarnings("serial")
	public class IllegalDogStateException extends RuntimeException {

		public IllegalDogStateException(String message) {
			super(message);
		}

	}

	private final int weight;
	private final int age;
	private final String name;
	private final Breed breed;
	private final double droolCoefficient;

	public Dog(DogBuilder dogBuilder) {
		if (dogBuilder.weight < 1)
			throw new IllegalDogStateException("Weight must be greater than 0");
		if (dogBuilder.age < 1)
			throw new IllegalDogStateException("Age must be greater than 0");
		if (dogBuilder.breed == null)
			throw new IllegalDogStateException("Breed must be assigned");

		weight = dogBuilder.weight;
		age = dogBuilder.age;
		name = dogBuilder.name;
		breed = dogBuilder.breed;
		droolCoefficient = dogBuilder.droolCoefficient;
	}

	public int getWeight() {
		return weight;
	}

	public int getAge() {
		return age;
	}

	public String getName() {
		return name;
	}

	public Breed getBreed() {
		return breed;
	}

	public double getDroolCoefficient() {
		return droolCoefficient;
	}

	@Override
	public String toString() {
		String formatString = "A %s Named %s who is %d years old and weighs %d pounds. A %s drooler";
		return String.format(formatString, breed, name, age, weight,
				droolWeight());
	}

	@Override
	public boolean equals(Object o) {
		if (o instanceof Dog == false)
			return false;

		if (this == o)
			return true;

		Dog dog = (Dog) o;

		if (dog.breed != breed)
			return false;

		if (dog.age != age)
			return false;

		if (dog.weight != weight)
			return false;

		return true;
	}

	@Override
	public int hashCode() {
		int hashcode = breed.hashCode();
		hashcode = 31 * hashcode + age;
		hashcode = 31 * hashcode + weight;
		return hashcode;
	}

	private String droolWeight() {
		if (droolCoefficient < .3)
			return "light";
		if (droolCoefficient < .6)
			return "medium";
		return "heavy";

	}

	public static class DogBuilder {

		private int weight;
		private int age;
		private String name = "";
		private Breed breed;
		private double droolCoefficient = 0;

		public DogBuilder weight(int weight) {
			this.weight = weight;
			return this;
		}

		public DogBuilder age(int age) {
			this.age = age;
			return this;
		}

		public DogBuilder name(String name) {
			this.name = name;
			return this;
		}

		public DogBuilder breed(Breed breed) {
			this.breed = breed;
			return this;
		}

		public DogBuilder droolCoefficient(double droolCoefficient) {
			this.droolCoefficient = droolCoefficient;
			return this;
		}

		public Dog build() {
			return new Dog(this);
		}
	}

}
